﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YasharEl.Infrastructure.ApplicationModel.Modularity.Bootstrap;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Configuration;
using YasharEl.Infrastructure.ObjectFactory.ServiceModel;
using YasharEl.Infrastructure.ServiceModel.Configuration;
using System.Configuration;
using System.ServiceModel.Configuration;

namespace YasharEl.Infrastructure.ApplicationModel.Service.Bootstrap.Extensions
{
    public class AutomaticSelfHostedWcfServicesBootstrappingExtension : ModuleComponentBootstrappingExtension, IConsumeConfigurationSection
    {
        #region Fields


        private Dictionary<Type, DependencyContainerServiceHost> _selfHostedWCFServices = new Dictionary<Type, DependencyContainerServiceHost>();

        private List<Type> _selfHostedWCFServicesTypes = new List<Type>();

        #endregion

        #region Properties

        public ServiceModelConfig ServiceModelConfigSection { get; private set; }

        #endregion

        #region IConsumeConfigurationSection Members

        public void Apply(ConfigurationSection section)
        {
            ServiceModelConfigSection = section as ServiceModelConfig;
        }

        #endregion

        #region ModuleComponentBootstrappingExtension Overrides

        public override string SectionName
        {
            get { return ServiceModelConfig.ServiceModelConfigDefaultSectionName; }
        }

        #endregion

        #region BaseComplexBootstrappingExtension Describe

        public override string Describe()
        {
            return "Bootstrapper extension which load and host wcf services in windows service application.";
        }

        #endregion

        #region BaseComplexBootstrappingExtension Configure, Start and Shutdown Methods

        public override void Start()
        {
            base.Start();

            if (_selfHostedWCFServicesTypes != null && _selfHostedWCFServicesTypes.Count > 0)
            {
                foreach (Type serviceType in _selfHostedWCFServicesTypes)
                {
                    DependencyContainerServiceHost serviceHost = new DependencyContainerServiceHost(
                        serviceType,
                        Container.DependencyResolver,
                        Container.DependencyRegistrar
                    );
                    try
                    {
                        serviceHost.Open();
                        _selfHostedWCFServices.Add(serviceType, serviceHost);
                        Logger.Debug("Service {0} opened and listening...", serviceType);
                    }
                    catch (Exception e)
                    {
                        string message = string.Format("Application could not open {0} service.", serviceType);
                        Logger.Fatal(e, message);

                        serviceHost.Abort();
                        throw new InvalidSystemConfigurationException(message, e);
                    }
                }
            }
        }

        public override void Shutdown()
        {
            base.Shutdown();

            foreach (DependencyContainerServiceHost service in _selfHostedWCFServices.Values)
            {
                try
                {
                    service.Close();
                    Logger.Debug("Service {0} closed.", service.Description.ConfigurationName);
                }
                catch (Exception e)
                {
                    service.Abort();
                    Logger.Warn(e, "Service {0} aborted.", service.Description.ConfigurationName);
                }
            }
        }

        public override void Configure()
        {
            base.Configure();

            try
            {
                if (ServiceModelConfigSection != null &&
                    ServiceModelConfigSection.Hosting != null &&
                    ServiceModelConfigSection.Hosting.SelfHostedServices != null &&
                    ServiceModelConfigSection.Hosting.SelfHostedServices.Count > 0)
                {
                    ServicesSection servicesSection = System.Configuration.ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;

                    if (servicesSection == null)
                    {
                        Logger.Warn("system.serviceModel/services section not defined.");
                        return;
                    }
                    foreach (SelfHostedServiceConfig selfHostedServiceConfig in ServiceModelConfigSection.Hosting.SelfHostedServices)
                    {
                        if (selfHostedServiceConfig.Enabled)
                        {
                            Logger.Info("Hosting {0} service...", selfHostedServiceConfig.ServiceName);

                            if (!servicesSection.Services.ContainsKey(selfHostedServiceConfig.ServiceName))
                            {
                                Logger.Warn("Service with name '{0}' not exists in system.serviceModel/services section and will ignored(not hosted). Check you configuration files(s).", selfHostedServiceConfig.ServiceName);
                            }
                            else
                            {
                                _selfHostedWCFServicesTypes.Add(selfHostedServiceConfig.ServiceType);
                            }
                        }
                    }
                }
                else
                {
                    Logger.Warn("AutomaticSelfHostedWcfServicesBootstrappingExtension registered but no configuration found related to the feature. Must use yasharEl.infrastructure.serviceModel section with defined self hosted services inside.");
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error configuring wcf auto self hosting feature.");
                throw new InvalidSystemConfigurationException("Error configuring wcf auto self hosting feature.", ex);
            }
        }

        #endregion
    }
}
